package ebedynky.services;

import ebedynky.beans.HibernateUtil;
import ebedynky.beans.Customer;
import ebedynky.beans.Message;
import ebedynky.beans.Offer;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

/**
 * @author davidon1
 */
public class CustomerService {

    /**
     * Seesion - current connection to the db.
     */
    private Session session;

    /**
     * Constructor, retrieves the session (connection).
     */
    public CustomerService() {
        this.session = HibernateUtil.getSessionFactory().openSession();
    }

    /**
     * Closes the session (connection).
     * @return success/failure.
     */
    public boolean close() {
        this.session.close();
        return !(this.session.isOpen());
    }

    /**
     * Restarts the session (connection).
     * @return success/failure.
     */
    public boolean restart() {
        this.session.close();
        if (this.session.isOpen()) {
            throw new IllegalStateException("Session could not be closed.");
        }
        this.session = HibernateUtil.getSessionFactory().openSession();
        return this.session.isOpen();
    }

    /**
     * Adds Customer to the db.
     * @param cus Customer to be inserted
     * @return ID of the added Customer
     */
    public int addCustomer(Customer cus) {
        session.beginTransaction();
        int id = getMaxCustomerID() + 1;
        cus.setCustomerID(id);
        id = (Integer) session.save(cus);
        session.getTransaction().commit();
        return (id);
    }

    /**
     * Retrieves the maximum id currently in the database of Customers.
     * @return Max ID
     */
    public int getMaxCustomerID() {
        String hql = "select max(u.userID) from User u";
        List list = session.createQuery(hql).list();
        if (list.get(0) != null) {
            Integer maxcusid = (Integer) list.get(0);
            return maxcusid;
        } else {
            return 0;
        }
    }

    /**
     * Retrieves a Customer identified by the ID.
     * @param id of the Customer
     * @return Customer with the ID given (null if not found)
     */
    public Customer getCustomerByID(int id) {
        session.beginTransaction();
        Customer cus = (Customer) session.get(Customer.class, new Integer(id));
        session.getTransaction().commit();
        return (cus);
    }

    /**
     * Retrieves a list of all Customers stored in the db.
     * @return List of all Customers (null if no Customers)
     */
    public List<Customer> getAllCustomers() {
        session.beginTransaction();
        List<Customer> cusList = session.createQuery("from Customer").list();
        session.getTransaction().commit();
        return (cusList);
    }

    /**
     * Updates a specified Customer identified by ID.
     * @param newCustomer an updated Customer
     */
    public void updateCustomer(Customer newCustomer) {
        session.beginTransaction();
        Customer cus = (Customer) session.get(Customer.class, new Integer(newCustomer.getUserID()));
        cus.setAccountState(newCustomer.getAccountState());
        cus.setRoles(newCustomer.getRoles());
        cus.setStreet(newCustomer.getStreet());
        cus.setStreetNo(newCustomer.getStreetNo());
        cus.setCity(newCustomer.getCity());
        cus.setZip(newCustomer.getZip());
        cus.setEmail(newCustomer.getEmail());
        cus.setFroms(newCustomer.getFroms());
        cus.setName(newCustomer.getName());
        cus.setPass(newCustomer.getPass());
        cus.setSurname(newCustomer.getSurname());
        cus.setTos(newCustomer.getTos());
        cus.setUsername(newCustomer.getUsername());
        cus.setBoxorders(newCustomer.getBoxorders());
        cus.setGranges(newCustomer.getGranges());
        session.flush();
        session.getTransaction().commit();
        session.clear();
    }

    /**
     * Removes the Customer from db.
     * @param id Customer ID for removal
     * @return true if successful, false otherwise
     */
    public boolean deleteCustomer(int id) {
        try {
            session.beginTransaction();
            Customer cus = (Customer) session.get(Customer.class, new Integer(id));
            session.delete(cus);
            session.getTransaction().commit();
            return (true);
        } catch (HibernateException ex) {
            return (false);
        }
    }

    /**
     * Returns all messages that were aimed to this customer.
     * @param customer for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getToMessages(Customer cus) {
        if (cus == null || cus.getTos() == null || cus.getTos().isEmpty())
            return new ArrayList<Message>(0);
        return new ArrayList<Message>(cus.getTos());
    }

    /**
     * Returns all messages that were aimed to this customer.
     * @param id for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getToMessages(int id) {
        return getToMessages(getCustomerByID(id));
    }

    /**
     * Returns all messages that were aimed from this customer.
     * @param customer for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getFromMessages(Customer cus) {
        if (cus == null || cus.getFroms() == null || cus.getFroms().isEmpty())
            return new ArrayList<Message>(0);
        return new ArrayList<Message>(cus.getFroms());
    }

    /**
     * Returns all messages that were aimed from this customer.
     * @param id for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getFromMessages(int id) {
        return getFromMessages(getCustomerByID(id));
    }

    /**
     * Returns all messages that were aimed to/from this customer.
     * @param customer for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getAllMessages(Customer cus) {
        if (cus == null || cus.getTos() == null || cus.getTos().isEmpty())
            return new ArrayList<Message>(0);
        ArrayList<Message> am = new ArrayList<Message>(cus.getTos());
        if (cus.getFroms() != null && !cus.getFroms().isEmpty())
            am.addAll(cus.getFroms());
        return am;
    }

    /**
     * Returns all messages that were aimed to/from this customer.
     * @param id for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getAllMessages(int id) {
        return getFromMessages(getCustomerByID(id));
    }

    /**
     * Returns all unread messages that were aimed to this customer.
     * @param customer for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getAllUnreadMessages(Customer cus) {
        if (cus == null || cus.getTos() == null || cus.getTos().isEmpty())
            return new ArrayList<Message>(0);
        ArrayList<Message> am = new ArrayList<Message>(cus.getTos());
        for (Message m : am)
            if (!m.isUnread())
                am.remove(m);
        return am;
    }

    /**
     * Returns all unread messages that were aimed to this customer.
     * @param id for whom the messages are to be found
     * @return list of messages
     */
    public List<Message> getAllUnreadMessages(int id) {
        return getAllUnreadMessages(getCustomerByID(id));
    }

    //TODO TEST???
    /**
     * Returns all offers currently available for this customer.
     * @param customer for whom the available are to be found
     * @return list of offers
     */
    public List<Offer> getAllAvailableOffers(Customer cus) {
        session.beginTransaction();
        String now = (new Timestamp(System.currentTimeMillis())).toString();
        List<Offer> oList = session.createQuery(
                "from Offer o "
                + "where (o.subsupply=false and "
                + "o.validFrom>" + now + " and "
                + "o.validUntil<" + now + ')'
                ).list();
        session.getTransaction().commit();
        return oList;
    }

    /**
     * Returns all offers currently available for this customer.
     * @param id for whom the available are to be found
     * @return list of offers
     */
    public List<Offer> getAllAvailableOffers(int id) {
        return getAllAvailableOffers(getCustomerByID(id));
    }
}
